#pragma once
#include<unordered_map>
#include<memory>
#include"util.hpp"
#include<mutex>
#include"logger.hpp"
enum ss_statu
{
    UNLOGIN,
    LOGIN
};
class session
{
    public:
    session(uint64_t ssid)
    :_ssid(ssid)
    {
    }
    ~session()
    {}
    void Set_Statu(ss_statu statu)
    {
        _statu=statu;
    }
    void Set_User(uint64_t uid)
    {
        _uid=uid;
    }
    uint64_t GetUser()
    {
        return _uid;
    }
    bool IsLogin()
    {
        return (_statu==LOGIN);
    }
    void SetTimer(wsserver_t::timer_ptr timer)
    {
        _timer=timer;
    }
    wsserver_t::timer_ptr GetTimer()
    {
        return _timer;
    }
    uint64_t Get_ssid()
    {
        return _ssid;
    }   
    private:
    //session的唯一标识，由session_manager负责分配
    uint64_t _ssid;
    //关联的用户id
    uint64_t _uid;
    //用户（session）的状态：已登录/未登录
    ss_statu _statu;
    //定时器
    wsserver_t::timer_ptr _timer;
};


#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1
typedef std::shared_ptr<session> session_ptr;
class session_manager
{
    public:
    session_manager(wsserver_t* server)
    :_server(server)
    ,_next_ssid(1)
    {}
    ~session_manager(){}
    //创建并管理一个session对象
    session_ptr Create_session(uint64_t uid,ss_statu statu=LOGIN)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        session_ptr ptr(new session(_next_ssid));
        ptr->Set_Statu(statu);
        ptr->Set_User(uid);
        _sessions.insert(std::make_pair(_next_ssid, ptr));
        DBG_LOG("session： %ld 创建成功",_next_ssid);
        _next_ssid++;
        return ptr;
    }
    //利用ssid获取一个session对象
    session_ptr Get_by_ssid(uint64_t ssid)
    {
        auto pos=_sessions.find(ssid);
        if(pos==_sessions.end())
        {
            return  session_ptr();
        }
        return pos->second;
    }
    //删除一个session对象
    void Remove_session(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto pos=_sessions.find(ssid);
        if(pos==_sessions.end())
        {
            DBG_LOG("不存在可删除的对象！！");
            return;
        }
        _sessions.erase(ssid);
        DBG_LOG("session %ld 销毁成功",ssid);
    }

    void append_session(const session_ptr &ssp) 
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _sessions.insert(std::make_pair(ssp->Get_ssid(), ssp));
    }

    //设置session的过期时间
    void Set_expeir_time(uint64_t ssid,int sec)
    {
        session_ptr ssp=Get_by_ssid(ssid);
        if(ssp.get()==nullptr)
        {
            DBG_LOG("无相关可操作session!!");
            return;
        }
        wsserver_t::timer_ptr tp=ssp->GetTimer();
        //session一共有两种状态：1.永久存在（_timer为空） 2.截至时间后销毁
        //所以我们需要处理4种情况
        if(tp.get()==nullptr&&sec==SESSION_FOREVER)
        {
            //1.永久存在（_timer为空）->永久存在
            return;
        }
        else if(tp.get()==nullptr&&sec!=SESSION_FOREVER)
        {
            //2.永久存在（_timer为空）->截至时间后销毁
            wsserver_t::timer_ptr temp_timer=
            _server->set_timer(sec,std::bind(&session_manager::Remove_session,this,ssid));
            ssp->SetTimer(temp_timer);
        }
        else if(tp.get()!=nullptr&&sec!=SESSION_FOREVER)
        {
            //3.截至时间后销毁->截至时间后销毁
            tp->cancel();
            _server->set_timer(0,std::bind(&session_manager::append_session,this,ssp));
            wsserver_t::timer_ptr temp_timer=
            _server->set_timer(sec,std::bind(&session_manager::Remove_session,this,ssp->Get_ssid()));
            ssp->SetTimer(temp_timer);
        }
        else if(tp.get()!=nullptr&&sec==SESSION_FOREVER)
        {
            //4.截至时间后销毁->永久存在（_timer为空）
            tp->cancel();
            _server->set_timer(0,std::bind(&session_manager::append_session,this,ssp));
            wsserver_t::timer_ptr temp_timer=wsserver_t::timer_ptr();
            ssp->SetTimer(temp_timer);
            DBG_LOG("session:%ld 设置截止时间为:%d",ssid,sec);
        }
    }
    private:
    //ssid的计数器
    uint64_t _next_ssid;
    //互斥锁
    std::mutex _mutex;
    //建立ssid与session的映射关系
    std::unordered_map<uint64_t,session_ptr> _sessions;
    //一个websocket连接对象
    wsserver_t* _server;
};